﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WcfGeebaServer.ContentManage;
using WcfGeebaServer.Users;
using WcfGeebaServer.Policies;
using WcfGeebaServer.DBDAL;

namespace TestGeeba
{
    /// <summary>
    /// This is a test class for GForum and is intended
    /// to contain all GForum Unit Tests
    /// </summary>
    [TestClass]
    public class GForumTest
    {
        private Member member;
        private GForum testedForum;
        private TestContext testContext;

        public GForumTest()
        {
            Data.ClearDB();
            testedForum = GForum.GetForum();
            testedForum.init(new Member("boris", "1234", true), new GPolicy());

            MemberDA.getMemberDA().AddMember("user", "1234");
            member = new Member("user", "1234", true);
        }

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContext;
            }
            set
            {
                testContext = value;
            }
        }

        public GForum TestedForum
        {
            get
            {
                return testedForum;
            }
            set
            {
                testedForum = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void initTest()
        {
            Assert.IsTrue(testedForum.addSubForum("subForumToSeeForumIsInitialized", member));
        }

        [TestMethod]
        public void addSubForumTest()
        {

            Assert.IsTrue(testedForum.addSubForum("test1", member));
            Assert.IsTrue(testedForum.addSubForum("test2", member));
            Assert.IsTrue(testedForum.getSubForums().Contains(new GSubForum("test1")));
            Assert.IsFalse(testedForum.getSubForums().Contains(new GSubForum("not there")));
            Assert.IsTrue(testedForum.getSubForums().Contains(new GSubForum("test2")));
        }

        [TestMethod]
        public void getSubForumsTest()
        {
            int count = (testedForum.getSubForums() == null) ? 0 : testedForum.getSubForums().Count;
            string topic = "new topic 1";
            testedForum.addSubForum(topic, member);
            Assert.IsTrue(testedForum.getSubForums().Count == count + 1);
            Assert.IsTrue(testedForum.getSubForums().Contains(new GSubForum(topic)));
        }

        [TestMethod]
        public void removeSubForumTest()
        {
            testedForum.addSubForum("AAA", member);
            testedForum.addSubForum("BBB", member);
            testedForum.addSubForum("CCC", member);
            Assert.IsTrue(testedForum.getSubForums().Contains(new GSubForum("AAA")));
            Assert.IsTrue(testedForum.getSubForums().Contains(new GSubForum("BBB")));
            Assert.IsTrue(testedForum.getSubForums().Contains(new GSubForum("CCC")));
            Assert.IsFalse(testedForum.getSubForums().Contains(new GSubForum("not there")));
            testedForum.removeSubForum("AAA");
            Assert.IsFalse(testedForum.getSubForums().Contains(new GSubForum("AAA")));
            testedForum.removeSubForum("BBB");
            Assert.IsFalse(testedForum.getSubForums().Contains(new GSubForum("BBB")));
        }

        [TestMethod]
        public void registerTest()
        {
            Assert.IsFalse(testedForum.register("guest", "123"));
            Assert.IsFalse(testedForum.register("guest123", "123"));
            Assert.IsFalse(testedForum.register("GuEsTBLABLA", "123"));
            Assert.IsTrue(testedForum.register("okToRegister", "123"));
            Assert.IsFalse(testedForum.register("okToRegister", "123"));
        }

        [TestMethod]
        public void loginTest()
        {
            User user = testedForum.entry();
            Assert.AreNotEqual(testedForum.login(user, "boris", "1234"), null);
            try
            {
                Assert.AreEqual(testedForum.login(user, "boris", "12345"), null);
            }
            catch { }
            Assert.IsFalse(testedForum.CurrGuests.Contains(user));
            Assert.IsTrue(testedForum.LoggedMembers.Contains(new Member("boris", "1234", true)));
        }

        [TestMethod]
        public void changeMemberPasswordTest()
        {
            testedForum.register("aMemberToChangePassword", "1234");
            Assert.IsTrue(testedForum.changeMemberPassword("aMemberToChangePassword", "1234", "4321"));
            Assert.IsFalse(testedForum.changeMemberPassword("aMemberToChangePassword", "1234", "4321"));
            Assert.IsTrue(testedForum.changeMemberPassword("aMemberToChangePassword", "4321", "1234"));
        }

        [TestMethod]
        public void entryTest()
        {
            // just testing for different names
            Assert.IsFalse(testedForum.entry().Equals(testedForum.entry()));
            Assert.IsFalse(testedForum.entry().Equals(testedForum.entry()));
            Assert.IsFalse(testedForum.entry().Equals(testedForum.entry()));
        }

        [TestMethod]
        public void logoutTest()
        {
            User user = testedForum.entry();
            Member member = testedForum.login(user, "boris", "1234");
            Assert.IsFalse(testedForum.logout(member) == null);
            Assert.IsFalse(testedForum.LoggedMembers.Contains(new Member("boris123", "1234", true)));
        }

        [TestMethod]
        public void getThreadsTest()
        {
            int sfcount = 0;
            if (testedForum.getSubForums() != null)
                sfcount = testedForum.getSubForums().Count;
            GSubForum subForum = new GSubForum("Topic");
            testedForum.addSubForum("Topic", member);
            Assert.IsTrue(testedForum.getSubForums().Count == sfcount + 1);
            int tcount = 0;
            if (testedForum.getThreads(subForum) != null)
                tcount = testedForum.getThreads(subForum).Count;
            testedForum.register("eyal", "1234");
            subForum.publish(new GThread("Message 1", "This is a test message", new Member("eyal", "1234", true)));
            Assert.IsTrue(testedForum.getThreads(subForum).Count == tcount + 1);
            testedForum.register("gili", "1234");
            subForum.publish(new GThread("Message 1", "This is a test message", new Member("gili", "1234", true)));
            Assert.IsTrue(testedForum.getThreads(subForum).Count == tcount + 2);
        }

        [TestMethod]
        public void replaceAdminTest()
        {
            Member oldAdmin = testedForum.Admin;
            Member newAdmin = new Member("alex", "1234", true);
            Assert.IsTrue(testedForum.register("alex", "1234"));
            Assert.IsFalse(testedForum.replaceAdmin(null));
            Assert.IsTrue(testedForum.replaceAdmin(newAdmin));
            Assert.IsFalse(testedForum.Admin.Equals(oldAdmin));
            Assert.IsTrue(testedForum.Admin.Equals(newAdmin));
            Assert.IsTrue(testedForum.replaceAdmin(oldAdmin));
            Assert.IsTrue(testedForum.Admin.Equals(oldAdmin));
            Assert.IsFalse(testedForum.Admin.Equals(newAdmin));
        }

        [TestMethod]
        public void GetThreadCountTest()
        {
            string username = "aMemberForThreadCount";
            Member newMember = new Member(username, "123", true);
            testedForum.register(username, "123");
            Assert.IsTrue(testedForum.GetThreadCount(username) == 0);
            Assert.IsTrue(testedForum.addSubForum("sfForTesting", member));
            GSubForum sf = testedForum.getSubForum("sfForTesting");
            Assert.IsNotNull(sf);
            sf.publish(new GThread("subject 1", "content 1", newMember));

            sf.publish(new GThread("subject 2", "content 2", newMember));
            sf.publish(new GThread("subject 3", "content 3", newMember));
            Assert.IsTrue(testedForum.GetThreadCount(username) == 3);
        }

        [TestMethod]
        public void GetMemberTest()
        {
            string aMember = "aGetMemberTest";
            testedForum.register(aMember, "bla");
            Assert.AreEqual(new Member(aMember, "bla", true), testedForum.GetMember(aMember));
        }

        [TestMethod]
        public void getSubForumTest()
        {
            string topic = "aTopicForGetSubForum";
            testedForum.addSubForum(topic, member);
            Assert.AreEqual(new GSubForum(topic), testedForum.getSubForum(topic));
            string topic2 = "aTopicForGetSubForum123";
            testedForum.addSubForum(topic2, member);
            Assert.AreEqual(new GSubForum(topic2), testedForum.getSubForum(topic2));
        }

        [TestMethod]
        public void IsMemberTest()
        {
            string username = "isMemberTest";
            testedForum.register(username, "bla");
            Assert.IsTrue(testedForum.IsMember(username));
            Assert.IsFalse(testedForum.IsMember("guest")); // can never be a member
        }

        [TestMethod]
        public void getConnectedMembersCountTest()
        {
            string user1 = "memberToConnect1";
            string user2 = "memberToConnect2";
            string user3 = "memberToConnect3";
            string password = "123";
            Assert.IsTrue(testedForum.register(user1, password));
            Assert.IsTrue(testedForum.register(user2, password));
            Assert.IsTrue(testedForum.register(user3, password));
            int count = testedForum.getConnectedMembersCount();
            Member m1, m2, m3;
            Assert.IsTrue((m1 = testedForum.login(testedForum.entry(), user1, password)) != null);
            Assert.IsTrue(testedForum.getConnectedMembersCount() == count + 1);
            Assert.IsTrue((m2 = testedForum.login(testedForum.entry(), user2, password)) != null);
            Assert.IsTrue(testedForum.getConnectedMembersCount() == count + 2);
            Assert.IsTrue((m3 = testedForum.login(testedForum.entry(), user3, password)) != null);
            Assert.IsTrue(testedForum.getConnectedMembersCount() == count + 3);
            testedForum.logout(m1);
            Assert.IsTrue(testedForum.getConnectedMembersCount() == count + 2);
            testedForum.logout(m2);
            Assert.IsTrue(testedForum.getConnectedMembersCount() == count + 1);
            testedForum.logout(m3);
            Assert.IsTrue(testedForum.getConnectedMembersCount() == count);
        }

        [TestMethod]
        public void searchByContentTest()
        {

            string user1 = "memberToConnect1";
            string user2 = "memberToConnect2";
            string user3 = "memberToConnect3";
            string password = "123";
            Assert.IsTrue(testedForum.register(user1, password));
            Assert.IsTrue(testedForum.register(user2, password));
            Assert.IsTrue(testedForum.register(user3, password));
            int count = testedForum.getConnectedMembersCount();
            Member m1, m2, m3;
            Assert.IsTrue((m1 = testedForum.login(testedForum.entry(), user1, password)) != null);
            Assert.IsTrue((m2 = testedForum.login(testedForum.entry(), user2, password)) != null);
            Assert.IsTrue((m3 = testedForum.login(testedForum.entry(), user3, password)) != null);

            GSubForum sub = new GSubForum("a");
            testedForum.addSubForum(sub.Topic, m1);

            GThread thread = new GThread("a1", "b1", m1);
            GThread thread2 = new GThread("a1", "b1 some words", m2);
            GThread thread3 = new GThread("a1", "b2 some words b1", m3);
            GThread thread4 = new GThread("a1", "b2 some words", m1);
            sub.publish(thread);
            sub.publish(thread2);
            sub.publish(thread3);
            sub.publish(thread4);
            
            Assert.IsTrue(testedForum.searchByContent("b1").Count == 3);
        }

        [TestMethod]
        public void searchByUserTest()
        {

            string user1 = "memberToConnect1";
            string user2 = "memberToConnect2";
            string user3 = "memberToConnect3";
            string password = "123";
            Assert.IsTrue(testedForum.register(user1, password));
            Assert.IsTrue(testedForum.register(user2, password));
            Assert.IsTrue(testedForum.register(user3, password));
            int count = testedForum.getConnectedMembersCount();
            Member m1, m2, m3;
            Assert.IsTrue((m1 = testedForum.login(testedForum.entry(), user1, password)) != null);
            Assert.IsTrue((m2 = testedForum.login(testedForum.entry(), user2, password)) != null);
            Assert.IsTrue((m3 = testedForum.login(testedForum.entry(), user3, password)) != null);

            GSubForum sub = new GSubForum("a");
            testedForum.addSubForum(sub.Topic, m1);

            GThread thread = new GThread("a1", "b1", m1);
            GThread thread2 = new GThread("a1", "b1 some words", m2);
            GThread thread3 = new GThread("a1", "b2 some words b1", m3);
            GThread thread4 = new GThread("a1", "b2 some words", m1);
            sub.publish(thread);
            sub.publish(thread2);
            sub.publish(thread3);
            sub.publish(thread4);

            Assert.IsTrue(testedForum.searchByUser(m1.Username).Count == 2);
            Assert.IsTrue(testedForum.searchByUser(m2.Username).Count == 1);
            Assert.IsTrue(testedForum.searchByUser(m3.Username).Count == 1);
        }
    }
}
